package com.gitee.wsl.struct.tree

import com.gitee.wsl.struct.tree.TreeNodeManager.areAllNulls
import kotlin.math.max

abstract class CategoryTreeNode(data: Any?) : TreeNode(data), Iterable<TreeNode> {

    var isLazyLoadData:Boolean = false

    var isLazyDataLoaded:Boolean = false

    var isExpand:Boolean = false

    fun shrink() {
        isExpand = false
    }

    fun toggle(): Boolean {
        isExpand = !isExpand
        return isExpand
    }

    /**
     * Checks whether among the current tree node subtrees there is
     * a specified subtree
     *
     * @param subtree subtree whose presence within the current tree
     * node children is to be checked
     * @return `true` if among the current tree node subtrees
     * there is a specified subtree; `false` otherwise
     */
    open fun hasSubtree(subtree: TreeNode): Boolean {
        if (isLeaf || subtree.isRoot) {
            return false
        }
        for (mSubtree in subtrees()) {
            if (mSubtree == subtree) {
                return true
            }
        }
        return false
    }

    /**
     * Checks whether the current tree node with all of its descendants
     * (entire tree) contains the specified node
     *
     * @param node node whose presence within the current tree node with
     * all of its descendants (entire tree) is to be checked
     * @return `true` if the current node with all of its descendants
     * (entire tree) contains the specified node; `false`
     * otherwise
     */
    override operator fun contains(node: TreeNode): Boolean {
        if (isLeaf || node.isRoot) {
            return false
        }
        for (subtree in subtrees()) {
            if (subtree == node || subtree.contains(node)) {
                return true
            }
            /*if(subtree instanceof CategoryTreeNode){
                if(((CategoryTreeNode<T,K>)subtree).contains(node))
                    return true;
            }*/
        }
        return false
    }

    /**
     * Checks whether the current tree node with all of its descendants
     * (entire tree) contains all of the nodes from the specified collection
     * (the place of nodes within a tree is not important)
     *
     * @param nodes collection of nodes to be checked for containment
     * within the current tree node with all of its descendants
     * (entire tree)
     * @return `true` if the current tree node with all of its
     * descendants (entire tree) contains all of the nodes from the
     * specified collection; `false` otherwise
     */
    fun containsAll(nodes: List<TreeNode>): Boolean {
        if (isLeaf || areAllNulls(nodes)) {
            return false
        }
        for (node in nodes) {
            if (!contains(node)) {
                return false
            }
        }
        return true
    }

    /**
     * Removes the first occurrence of the specified node from the entire tree,
     * starting from the current tree node and traversing in a pre order manner
     *
     *
     * Checks whether the current tree node was changed as a result of the call
     *
     * @param node node to remove from the entire tree
     * @return `true` if the current tree node was changed as a result of
     * the call; `false` otherwise
     */
    override fun remove(node: TreeNode): Boolean {
        if ( isLeaf || node.isRoot) {
            return false
        }
        if (dropSubtree(node)) {
            return true
        }
        for (subtree in subtrees()) {
            if (subtree.remove(node)) {
                return true
            }
            /*if(subtree instanceof CategoryTreeNode){
                if(((CategoryTreeNode<T,K>)subtree).remove(node))
                    return true;
            }*/
        }
        return false
    }

    /**
     * Removes all of the collection's nodes from the entire tree, starting from
     * the current tree node and traversing in a pre order manner
     *
     *
     * Checks whether the current tree node was changed as a result of the call
     *
     * @param nodes collection containing nodes to be removed from the entire tree
     * @return `true` if the current tree node was changed as a result
     * of the call; `false` otherwise
     */
    fun removeAll(nodes: List<TreeNode>): Boolean {
        if (isLeaf || areAllNulls(nodes)) {
            return false
        }
        var result = false
        for (node in nodes) {
            val currentResult = remove(node)
            if (!result && currentResult) {
                result = true
            }
        }
        return result
    }

    /*override fun getChildren(): List<TreeNode> {
        return subtrees()
    }*/

    /**
     * Returns the collection of the child nodes of the current node
     * with all of its proper descendants, if any
     *
     *
     * Returns [Collections.emptySet] if the current node is leaf
     *
     * @return collection of the child nodes of the current node with
     * all of its proper descendants, if any;
     * [Collections.emptySet] if the current node is leaf
     */
    open fun subtrees(): List<TreeNode> = children

    /**
     * Adds the subtree with all of its descendants to the current tree node
     *
     *
     * `null` subtree cannot be added, in this case return result will
     * be `false`
     *
     *
     * Checks whether this tree node was changed as a result of the call
     *
     * @param subtree subtree to add to the current tree node
     * @return `true` if this tree node was changed as a
     * result of the call; `false` otherwise
     */
    abstract fun add(subtree: TreeNode): Boolean

    /**
     * Drops the first occurrence of the specified subtree from the current
     * tree node
     *
     *
     * Checks whether the current tree node was changed as a result of
     * the call
     *
     * @param subtree subtree to drop from the current tree node
     * @return `true` if the current tree node was changed as a result
     * of the call; `false` otherwise
     */
    abstract fun dropSubtree(subtree: TreeNode): Boolean

    /**
     * Removes all the subtrees with all of its descendants from the current
     * tree node
     */
    abstract fun clear()

    /**
     * Returns an iterator over the elements in this tree in proper sequence
     *
     *
     * The returned iterator is **fail-fast**
     *
     * @return an iterator over the elements in this tree in proper sequence
     */
    override fun iterator(): Iterator<TreeNode> {
        return subtrees().iterator()
    }

    fun leafList(): List<TreeNode> {
        val leafList = ArrayList<TreeNode>()
        subtrees().forEach { subItemListItem: TreeNode ->
            if (subItemListItem.isLeaf) leafList.add(
                subItemListItem
            )
        }
        return leafList
    }

    fun categoryItemList(): Collection<TreeNode> {
        val parentList = ArrayList<TreeNode>()
        subtrees().forEach { subItemListItem: TreeNode ->
            if (!subItemListItem.isLeaf) parentList.add(
                subItemListItem
            )
        }
        return parentList
    }

    /**
     * Returns the number of nodes in the entire tree, including the current tree node
     *
     * @return number of nodes in the entire tree, including the current tree node
     */
    override fun size(): Long {
        if (isLeaf) {
            return 1
        }
        val count = longArrayOf(0)
        val action: TraversalAction<TreeNode> = object : TraversalAction<TreeNode> {
            override fun perform(node: TreeNode) {
                count[0]++
            }

            override val isCompleted: Boolean
                get() = false
        }
        traversePreOrder(this, action)
        return count[0]
    }

    /**
     * Returns the height of the current tree node, e.g. the number of edges
     * on the longest downward path between that node and a leaf
     *
     * @return height of the current tree node, e.g. the number of edges
     * on the longest downward path between that node and a leaf
     */
    override fun height(): Int {
        if (isLeaf) {
            return 0
        }
        var height = 0
        for (subtree in subtrees()) {
            height = max(height, subtree.height())
        }
        return height + 1
    }

    override fun traversePreOrder(node: TreeNode, action: TraversalAction<TreeNode>) {
        if (!action.isCompleted) {
            action.perform(node )
            if (!node.isLeaf && node is CategoryTreeNode) {
                node.subtrees().forEach{ subtree: TreeNode ->
                        traversePreOrder(subtree, action)
                    }
            }
        }
    }

    override fun traversePostOrder(node: TreeNode, action: TraversalAction<TreeNode>) {
        if (!action.isCompleted) {
            if (!node.isLeaf && node is CategoryTreeNode) {
                node.subtrees().forEach{ subtree: TreeNode ->
                    traversePostOrder(subtree, action)
                }
            }
            action.perform(node)
        }
    }
}